﻿using DotNet.Utilities;
using SimpleLogger;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace WPFTemplateLib.UserControls
{
    /// <summary>
    /// 信息区 用户控件
    /// </summary>
    public partial class UC_InfoRegion : UserControl
    {
        public UC_InfoRegion()
        {
            InitializeComponent();

            Task.Factory.StartNew(async () =>
            {
                foreach (string info in _BC.GetConsumingEnumerable())
                {
                    await ShowInfoTaskAsync(info);
                }
            }, TaskCreationOptions.LongRunning);
        }

        #region 成员

        /// <summary>
        /// 阻塞集合;
        /// </summary>
        private readonly BlockingCollection<string> _BC = new BlockingCollection<string>();

        #endregion

        #region 依赖属性

        #region 是否自动滚动

        public bool IsAutoScroll
        {
            get { return (bool)GetValue(IsAutoScrollProperty); }
            set { SetValue(IsAutoScrollProperty, value); }
        }

        public static readonly DependencyProperty IsAutoScrollProperty =
            DependencyProperty.Register("IsAutoScroll", typeof(bool), typeof(UC_InfoRegion), new PropertyMetadata(true));

        #endregion

        #region 是否记录到日志

        public bool IsRecordToLog
        {
            get { return (bool)GetValue(IsRecordToLogProperty); }
            set { SetValue(IsRecordToLogProperty, value); }
        }

        public static readonly DependencyProperty IsRecordToLogProperty =
            DependencyProperty.Register("IsRecordToLog", typeof(bool), typeof(UC_InfoRegion), new PropertyMetadata(false));

        #endregion

        #region 是否自动消息减半

        public bool IsAutoHalve
        {
            get { return (bool)GetValue(IsAutoHalveProperty); }
            set { SetValue(IsAutoHalveProperty, value); }
        }

        public static readonly DependencyProperty IsAutoHalveProperty =
            DependencyProperty.Register("IsAutoHalve", typeof(bool), typeof(UC_InfoRegion), new PropertyMetadata(true));

        #endregion

        #region 消息减半行数阈值

        /// <summary>
        /// 消息减半行数阈值
        /// </summary>
        public int AutoHalveLineThreshold
        {
            get { return (int)GetValue(AutoHalveLineThresholdProperty); }
            set { SetValue(AutoHalveLineThresholdProperty, value); }
        }

        public static readonly DependencyProperty AutoHalveLineThresholdProperty =
            DependencyProperty.Register("AutoHalveLineThreshold", typeof(int), typeof(UC_InfoRegion), new PropertyMetadata(10000));

        #endregion

        #region 当前要显示的文本

        public string InfoText
        {
            get { return (string)GetValue(InfoTextProperty); }
            set { SetValue(InfoTextProperty, value); }
        }

        public static readonly DependencyProperty InfoTextProperty =
            DependencyProperty.Register("InfoText", typeof(string), typeof(UC_InfoRegion),
                //new PropertyMetadata(null, InfoTextPropertyChangedCallback));
                //[WPF 自定义控件中自定义依赖属性 Binding 失效的问题](https://blog.csdn.net/q379809513/article/details/88782708)
                new FrameworkPropertyMetadata(null, InfoTextPropertyChangedCallback, InfoTextCoerceValueCallback) { BindsTwoWayByDefault = true }, null);

        private static bool InfoTextValidateValueCallback(object value)
        {
            return true;
        }

        /* 在【客户端绑定的值赋值后，值如果相同，手动调用变动触发通知（OnPropertyChanged）】的情况下；
         * 1、CoerceValueCallback 第一次触发，值不同，跳过，PropertyChangedCallback 触发，执行相关业务，后面 CoerceValueCallback 触发两次，值相同但需要排除；
         * 2、后续操作触发 CoerceValueCallback，如果值相同，执行相关业务，PropertyChangedCallback 不会触发；如果值不同，见步骤 1。
         */
        private bool _isSkiped = false;     //是否因为值不同，在 CoerceValueCallback 中跳过了；
        private bool _isChanged = false;    //是否因为值不同，在 PropertyChangedCallback 中改变了；

        private static object InfoTextCoerceValueCallback(DependencyObject d, object basevalue)
        {
            var that = (UC_InfoRegion)d;
            if (basevalue != null)
            {
                var oldValue = d.GetValue(InfoTextProperty);
                var newValue = basevalue;
                if (oldValue != newValue)
                {
                    that._isSkiped = true;
                }
                else
                {
                    if (!that._isSkiped && !that._isChanged)
                    {
                        that.AddInfo(basevalue + "");
                    }
                    else if (that._isSkiped)
                    {
                        that._isSkiped = false;
                    }
                    else if (that._isChanged)
                    {
                        that._isChanged = false;
                    }
                }
            }

            return basevalue;
        }

        private static void InfoTextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var that = (UC_InfoRegion)d;
            if (e.NewValue != null)
            {
                that.AddInfo(e.NewValue + "");
                that._isChanged = true;
            }
        }

        #endregion

        #endregion

        #region 辅助方法

        private async Task ShowInfoTaskAsync(string info, [CallerFilePath] string filePath = "", [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            try
            {
                await Dispatcher.InvokeAsync(() =>
                {
                    var lines = TBInfo.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();
                    if (lines.Count > AutoHalveLineThreshold && IsAutoHalve)
                    {
                        int removeLines = lines.Count - Math.Abs(AutoHalveLineThreshold) / 2;
                        lines.RemoveRange(0, removeLines);
                        TBInfo.Text = $"(已删除[{removeLines}]行信息){Environment.NewLine.Repeat(2)}" +
                                      string.Join(Environment.NewLine, lines);
                    }

                    int caretIndex = TBInfo.CaretIndex;
                    TBInfo.Text += $"[{DateTime.Now:HH:mm:ss.ffff}] {info}{Environment.NewLine}";
                    TBInfo.CaretIndex = caretIndex;

                    if (IsRecordToLog)
                    {
                        Task.Run(() =>
                        {
                            LogHelper.Write(info, true, filePath, memberName, lineNumber);
                        });
                    }
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        /// <summary>
        /// 添加新消息
        /// </summary>
        /// <param name="info">消息内容（为 null 时不处理）</param>
        public void AddInfo(string info)
        {
            if (info != null)
            {
                _BC.Add(info);
            }
        }

        #endregion

        #region 事件方法

        private void BtnClear_OnClick(object sender, RoutedEventArgs e)
        {
            TBInfo.Clear();
        }

        #endregion
    }

    //public class InfoRegionConverter : IMultiValueConverter
    //{
    //    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    //    {
    //        var uc = values[0] as UC_InfoRegion;
    //        uc.AddInfo(values[1] + "");
    //        return null;
    //    }

    //    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    //    {
    //        throw new NotImplementedException();
    //    }
    //}
}
